package com.me.study.javaCore.classLoader;

import com.me.common.util.SleepUtil;
import com.me.study.javaCore.classLoader.customClassLoader.MyClassLoader;
import org.apache.commons.lang3.RandomStringUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 自定义类加载器，重复加载同一个类，方法区存在两个 class对象，有各自的静态变量
 *
 * @author ME
 * @date 2021/7/6
 */
public class RepeatLoadClass {

    public static void main(String[] args) throws Exception {
        String className = "com.me.study.javaCore.classLoader.RepeatLoadClass$Person";

        MyClassLoader loader1 = new MyClassLoader();
        Class<Person> clazz1 = loadClass(loader1, className);
        Constructor<Person> constructor1 = clazz1.getConstructor(String.class);
        Object person1 = constructor1.newInstance("ljy");
        Field name1 = clazz1.getField("personName");
        name1.set(null, "ljy22");
        Method getPersonName1 = clazz1.getMethod("getPersonName");

        /** ====================================================== */
        MyClassLoader loader2 = new MyClassLoader();
        Class<Person> clazz2 = loadClass(loader2, className);
        Constructor<Person> constructor2 = clazz2.getConstructor(String.class);
        Object person2 = constructor2.newInstance("Tom");
        Field name2 = clazz2.getField("personName");
        name2.set(null, "Tom22");
        Method getPersonName2 = clazz2.getMethod("getPersonName");

        SleepUtil.seconds(1);
        System.out.println("ClassLoader 是否是多个：" + (loader1 != loader2));
        System.out.println("Class 是否是多个：" + (clazz1 != clazz2));
        System.out.println("Constructor 是否是多个：" + (constructor1 != constructor2));
        System.out.println("Person 是否是多个：" + (person1 != person2));

        System.out.println("\n多个类对象，各自的静态变量不一样");
        System.out.println(name1.get(person1));
        System.out.println(name2.get(null));

        System.out.println(getPersonName1.invoke(person1, null));
        System.out.println(getPersonName2.invoke(person2, null));

        System.out.println("ContextClassLoader：" + Thread.currentThread().getContextClassLoader());
    }

    /**
     * 设置指定的 类加载器 为 ContextClassLoader，并加载类信息
     * @param classLoader   类加载器
     * @param className     类的全限定类名
     * @param <T>   指定类型
     * @return  指定类型的类信息
     * @throws ClassNotFoundException   ClassNotFoundException
     */
    @SuppressWarnings("unchecked")
    private static <T> Class<T> loadClass(ClassLoader classLoader, String className) throws ClassNotFoundException {
        Thread.currentThread().setContextClassLoader(classLoader);

        return (Class<T>) Class.forName(className, false, classLoader);
    }

    public static class Person {
        public static String personName;

        public Person(String name) {
            Person.personName = name;
        }

        public static String getPersonName() {
            return personName + ":::" + RandomStringUtils.random(3, true, false);
        }
    }

}
